﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

namespace Comp376A2_9609695
{
    /// <summary>
    /// Rocks in the dirt
    /// </summary>
    public class Rock : Updateable, Drawable, Solid
    {
        public Vector2 position;
        public SpriteSheet spritesheet;
        public enum State { Static, Shaking, Falling, Broken, Clear };
        public State state;
        private int timer;
        private int shakeDelay;
        private int speed;
        public int squishCount = 0;
        protected Cue soundCue;
        protected SoundBank bank;
        public SoundBank soundbank
        {
            get { return bank; }
            set { bank = value; soundCue = soundbank.GetCue("squish"); }
        }
        private int frame;
        private int frameTime;
        private int frameLength;
        private Random r = new Random();
        private String animName;
        private List<int> animFrames;
        public String animation
        {
            get { return animName; }
            set
            {
                if (spritesheet.getAnimList().Contains(value))
                {
                    if (animName != value)
                    {
                        animName = value;
                        animFrames = spritesheet.getAnimation(animName);
                        frame = 0;
                        frameTime = 0;
                    }
                }
            }
        }

        public Rock(int startX, int startY, SpriteSheet sheet)
        {
            timer = 0;
            state = State.Static;
            position = new Vector2(startX, startY);
            spritesheet = sheet;
            speed = 32;
            frameLength = 200;
        }

        public void update(GameTime time, GameController control)
        {
            int elapsed = time.ElapsedGameTime.Milliseconds;
            timer += elapsed;
            Level level = control.level;
            DigDug player = control.player;
            // Get the cell below the rock and check the state
            byte cellBelow = level.getCellAt((int)position.X - level.X, (int)position.Y - level.Y + 16);
            switch (state)
            {
                case State.Static:
                    // If the rock is static, wait until the cell below is cleared, then shake
                    if (cellBelow != 0 && 
                        (player.position.X <= position.X - 16 || 
                        player.position.X >= position.X + 16 ||
                        player.position.Y >= position.Y + 25))
                    {
                        state = State.Shaking;
                        frameTime = 100;
                        timer = 0;
                        shakeDelay = r.Next(1000);
                    }
                    break;
                case State.Shaking:
                    // If the rock is shaking, delay, then shake, then fall
                    if (timer >= shakeDelay && animation == "rocksteady")
                    {
                        animation = "rockshake";
                        timer = 0;
                    }
                    if (timer >= 800 && animation == "rockshake")
                    {
                        state = State.Falling;
                        animation = "rocksteady";
                        if (soundCue.IsPrepared)
                            soundCue.Play();
                    }
                    break;
                case State.Falling:
                    // If the rock is falling, keep going until a solid cell is hit then break. 
                    cellBelow = level.getCell((int)(position.X - level.X) / 16, (int)(position.Y - level.Y) / 16 + 1);
                    if ((cellBelow != 0 || (int)(position.Y - level.Y) % 16 != 0) && (position.Y - level.Y) < 192)
                    {
                        position.Y += speed / elapsed;
                        byte cell = level.getCell((int)(position.X - level.X) / 16, (int)(position.Y - level.Y) / 16);
                        // Clear the top and bottom of cells on the way down
                        cell |= 10;
                        level.setCell((int)(position.X - level.X) / 16, (int)(position.Y - level.Y) / 16, cell);
                    }
                    else
                    {
                        state = State.Broken;
                        animation = "rockbreak";
                        frameLength = 750;
                        timer = 0;
                    }
                    break;
                case State.Broken:
                    // If the rock is broken, wait then clear it
                    if (timer >= 1400)
                        state = State.Clear;
                    break;
                default:
                    break;

            }
            frameTime += elapsed;
            if (frameTime >= frameLength)
            {
                frame = (frame + 1) % animFrames.Count;
                frameTime -= frameLength;
            }
        }

        public Texture2D getImage()
        {
            return spritesheet.image;
        }

        public void draw(SpriteBatch renderer)
        {
            if (state != State.Clear)
            {
                Rectangle sprite = spritesheet.getSprite(animFrames.ElementAt(frame));
                renderer.Draw(spritesheet.image, position, sprite, Color.White);
            }
        }

        public bool collides(Rectangle box)
        {
            if (state != State.Clear && state != State.Broken)
            {
                Rectangle bounds = new Rectangle((int)position.X + 1, (int)position.Y + 1, 14, 14);
                Rectangle intersection = new Rectangle();
                Rectangle.Intersect(ref box, ref bounds, out intersection);
                return (intersection.Width != 0 && intersection.Height != 0);
            }
            return false;
        }
    }
}
